package Model;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import Data.GameStatus;
import Data.Grid;
import Model.Pieces.*;

public class Game extends Observable{
	private ArrayList<Observer> obs;
	private Chessboard chessBoard;
	private List<Piece> black, white;
	private List<Piece> takenBlack, takenWhite;
	private GameStatus gameStatus;
	private int localPlayer;
	private GameType gameType;
	
	
	public Game(){
		obs = new ArrayList<Observer>();
		chessBoard = new Chessboard();
		black = new ArrayList<Piece>(16);
		white = new ArrayList<Piece>(16);
		takenBlack = new ArrayList<Piece>();
		takenWhite = new ArrayList<Piece>();
		//init();
		//chessBoard.addPieces(black);
		//chessBoard.addPieces(white);
	}
	
	
	private void init(){
		black.clear();
		white.clear();
		takenBlack.clear();
		takenWhite.clear();
		black.add(new Tower(new Point(0,0),Color.Black));
		black.add(new Knight(new Point(1,0),Color.Black));
		black.add(new Bishop(new Point(2,0),Color.Black));
		black.add(new Queen(new Point(3,0),Color.Black));
		black.add(new King(new Point(4,0),Color.Black));
		black.add(new Bishop(new Point(5,0),Color.Black));
		black.add(new Knight(new Point(6,0),Color.Black));
		black.add(new Tower(new Point(7,0),Color.Black));
		black.add(new Pawn(new Point(0,1),Color.Black));
		black.add(new Pawn(new Point(1,1),Color.Black));
		black.add(new Pawn(new Point(2,1),Color.Black));
		black.add(new Pawn(new Point(3,1),Color.Black));
		black.add(new Pawn(new Point(4,1),Color.Black));
		black.add(new Pawn(new Point(5,1),Color.Black));
		black.add(new Pawn(new Point(6,1),Color.Black));
		black.add(new Pawn(new Point(7,1),Color.Black));
		white.add(new Tower(new Point(0,7),Color.White));
		white.add(new Knight(new Point(1,7),Color.White));
		white.add(new Bishop(new Point(2,7),Color.White));
		white.add(new Queen(new Point(3,7),Color.White));
		white.add(new King(new Point(4,7),Color.White));
		white.add(new Bishop(new Point(5,7),Color.White));
		white.add(new Knight(new Point(6,7),Color.White));
		white.add(new Tower(new Point(7,7),Color.White));
		white.add(new Pawn(new Point(0,6),Color.White));
		white.add(new Pawn(new Point(1,6),Color.White));
		white.add(new Pawn(new Point(2,6),Color.White));
		white.add(new Pawn(new Point(3,6),Color.White));
		white.add(new Pawn(new Point(4,6),Color.White));
		white.add(new Pawn(new Point(5,6),Color.White));
		white.add(new Pawn(new Point(6,6),Color.White));
		white.add(new Pawn(new Point(7,6),Color.White));
		chessBoard.addPieces(black);
		chessBoard.addPieces(white);
	}
	
	public void launch(int localplayer){ // Add Strings for Players names init.
		this.gameStatus = new GameStatus(0, "Player1", "Player2");
		this.localPlayer = localplayer;
		this.chessBoard.clear();
		init();
		//this.gameStatus = new GameStatus(1 + (int)(Math.random() * ((2 - 1) + 1)), "Player1", "Player2",GameType.Local);
		
		notifyObserversGrid();
	}
	
	public boolean movePiece(Point startPoint, Point endPoint)
	{
		if(this.chessBoard.getPiece(startPoint) != null)
		{
			if(this.chessBoard.getPiece(startPoint).getColor() == Color.White && this.gameStatus.getNextPlayer() == 0
					|| this.chessBoard.getPiece(startPoint).getColor() == Color.Black && this.gameStatus.getNextPlayer() == 1)
			{
				if (movePiece(this.chessBoard.getPiece(startPoint), endPoint))
				{	
					return true;
				}
			}
		}
		return false;
	}
	
	public boolean movePiece(Piece p1, Point p2)
	{
		
		if(this.chessBoard.getPiece(p2) != null && this.chessBoard.getPiece(p2).getColor() == p1.getColor()){
			return false;
		}
		if(ChessboardMoves_utils.getPossibleMoves(this.chessBoard, p1).contains(p2))
		{
			if(this.chessBoard.getPiece(p2) != null)
			{
				if(this.chessBoard.getPiece(p2).getColor() == Color.Black)
				{
					this.takenBlack.add(this.chessBoard.getPiece(p2));
					this.black.remove(this.chessBoard.getPiece(p2));
					this.gameStatus.setScore(1, this.gameStatus.getScore(1)+1);
				}else{
					this.takenWhite.add(this.chessBoard.getPiece(p2));
					this.white.remove(this.chessBoard.getPiece(p2));
					this.gameStatus.setScore(0, this.gameStatus.getScore(0)+1);
				}
			}
			chessBoard.movePiece(p1.getPoint(), p2);
			notifyObserversGrid();
			//this.chessBoard.printBoard();
			return true;
		}
		return false;
	}
	
	public void notifyObserversGrid(){
		char charBoard [][] = new char[8][8];
		Piece board[][] = this.chessBoard.getBoard();
		for(int i=0 ; i<8 ; i++)
		{
			for(int j=0 ; j<8 ; j++)
			{
				if(board[i][j] == null)
				{
					charBoard[i][j] = 0;
				}else{
					if(board[i][j] instanceof Pawn)
					{
						charBoard[i][j] = 'p';
					}
					else if(board[i][j] instanceof Knight)
					{
						charBoard[i][j] = 'n';
					}
					else if(board[i][j] instanceof King)
					{
						charBoard[i][j] = 'k';
					}
					else if(board[i][j] instanceof Queen)
					{
						charBoard[i][j] = 'q';
					}
					else if(board[i][j] instanceof Tower)
					{
						charBoard[i][j] = 't';
					}
					else if(board[i][j] instanceof Bishop)
					{
						charBoard[i][j] = 'b';
					}
					
					if(board[i][j].getColor() == Color.Black)
					{
						charBoard[i][j] = Character.toUpperCase(charBoard[i][j]);
					}
				}
			}
		}
		Grid grid = new Grid(charBoard, null, null);
		for(Observer o : obs){
			o.update(null, grid);
		}
	}
	
	public void notifyObserversPossibleMoves(Point p)
	{
		boolean [][] boolBoard = new boolean[8][8];
		ArrayList<Point> pointList = null;
		if(this.chessBoard.getPiece(p) != null)
		{
			pointList = ChessboardMoves_utils.getPossibleMoves(this.chessBoard, this.chessBoard.getPiece(p));
			for(Point pl : pointList)
			{
				boolBoard[pl.x][pl.y] = true;
			}
			for(Observer o : obs){
				o.update(null, boolBoard);
			}
		}
	}
	
	public void addObserver(Observer obs){
		this.obs.add(obs);
	}
	
	public void removeObserver(Observer obs){
		this.obs.remove(obs);
	}
	
	public boolean isGameFinished()
	{
		for(Piece p : this.takenBlack)
		{
			if(p instanceof King)
			{
				gameStatus.setFinish(true);
				this.notifyObserversGameStatus();
				return true;
			}
		}
		for(Piece p : this.takenWhite)
		{
			if(p instanceof King)
			{
				gameStatus.setFinish(true);
				this.notifyObserversGameStatus();
				return true;
			}
		}
		this.notifyObserversGameStatus();
		return false;	
	}
	
	public GameStatus getGameStatus()
	{
		return gameStatus;
	}
	
	public void updateGameStatus(GameStatus gs)
	{
		this.gameStatus = gs;
	}
	
	public int getLocalPlayer()
	{
		return this.localPlayer;
	}
	
	public Color getPieceColor(Point p)
	{
		if(chessBoard.getPiece(p) != null)
			return this.chessBoard.getPiece(p).getColor();
		return null;
	}


	public GameType getGameType() {
		return gameType;
	}


	public void setGameType(GameType gameType) {
		this.gameType = gameType;
	}
	
	public void notifyObserversSelected(Point p)
	{
		Grid g = new Grid(null, null, p);
		for(Observer o : obs){
			o.update(null, g);
		}
	}


	public boolean analyzePoint(Point p) {
		if(chessBoard.getPiece(p) != null && (localPlayer == gameStatus.getNextPlayer() && gameType != GameType.Local || gameType == GameType.Local)){
			if(((chessBoard.getPiece(p).getColor() == Color.White && localPlayer == 0) || (chessBoard.getPiece(p).getColor() == Color.Black && localPlayer == 1)) && gameType != GameType.Local
					|| ((chessBoard.getPiece(p).getColor() == Color.Black && gameStatus.getNextPlayer() == 1 || chessBoard.getPiece(p).getColor() == Color.White && gameStatus.getNextPlayer() == 0) && gameType == GameType.Local)){
				notifyObserversSelected(p);
				return true;
			}
		}
		return false;
	}
	
	public void notifyObserversGameStatus()
	{
		for(Observer o : obs){
			o.update(null, gameStatus);
		}
	}
}
